#pragma once
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<cstring>
#include "Log.hpp"
#include<netinet/in.h> 
#include <arpa/inet.h>
#include<cstdlib>
   #include <signal.h>

enum
{
    SocketErr = 2,
    BindErr,
    ListenErr,
};

// TODO
const int backlog = 10;  //指定内核为相应套接字排队的最大连接个数为10 
class Sock
{
public:
    Sock()
    {
    }
    ~Sock()
    {
    }

public:
    void Socket() // 创建套接字
    {
        sockfd_ = socket(AF_INET, SOCK_STREAM , 0);
          if (sockfd_ < 0)
        {
            lg(Fatal, "socker error, %s: %d", strerror(errno), errno);
            exit(SocketErr);
        }


    }

    void Bind(uint16_t  port) // 服务端绑定端口
    {
        struct sockaddr_in   local ;
        memset( &local  , 0  , sizeof(local));
        local.sin_addr .s_addr = INADDR_ANY ;  //INADDR_ANY就是0 
         local.sin_family =AF_INET;
         local.sin_port = htons(port)  ;

            if(  bind(sockfd_ ,( struct sockaddr *) &local , sizeof(local)) < 0 )
            {
                  lg(Fatal, "bind error, %s: %d", strerror(errno), errno);
            exit(BindErr);
            } 


    }

    void Lisenten() // Tcp监听
    {

        if (listen(sockfd_, backlog) < 0)
        {
            lg(Fatal, "listen error, %s: %d", strerror(errno), errno);
            exit(ListenErr);
        }


    }
    int Accept(std::string *clientip, uint16_t *clientport) // Tcp接受客户端的连接请求
    {   
         struct sockaddr_in peer;
         socklen_t len = sizeof(peer) ;
            int newfd  =accept(sockfd_ ,(struct  sockaddr *) & peer , &len ); 
                  if(newfd < 0)
        {
            lg(Warning, "accept error, %s: %d", strerror(errno), errno);
            return -1;
        }

        char  ipstr [64] ;   
         //ipstr,len 这两个是用来防止inet_ntop报错的，没什么用
        inet_ntop(AF_INET , &peer.sin_addr,ipstr,len);//将四字节的整数IP转换成字符串IP
        //修改ip ,port
        *clientip = ipstr;
        *clientport = ntohs(peer.sin_port);  //网络序列转主机序列


     return newfd;

    }
    bool  Connect(const std::string &ip, const uint16_t &port) // 客户端向服务端发起连接请求时
    {
          struct sockaddr_in peer;
        memset( &peer  , 0  , sizeof(peer));

    peer.sin_family = AF_INET;
            peer.sin_port = htons(port);

   inet_pton(AF_INET, ip.c_str(), &(peer.sin_addr));//将一个点分十进制的IP地址字符串转换为网络字节顺序的数值形式

         socklen_t len = sizeof(peer) ;
            int n = connect(sockfd_,(struct sockaddr *)&peer ,len) ;

          if(n == -1) 
        {
            std::cerr << "connect to " << ip << ":" << port << " error" << std::endl;
            return false;
        }
        //发起连接成功
        return true;
    }
          void Close()
    {
        close(sockfd_);
    }
    int Fd()
    {
        return sockfd_;
    }
private:
    int sockfd_;
};